#include "stdafx.h"
#include "CreateCheckboxImageList.h"

namespace HDCheckboxImageList
{

///////////////////////////////////////////////////////////////////////////////
//
// CreateCheckboxImageList()
//
// Purpose:     Create themed checkbox image list
//
// Parameters:  pDC          - pointer to device context for drawing
//              imagelist    - image list to create
//              nSize        - height and width of images
//              crBackground - fill color
//
// Returns:     BOOL         - TRUE if image list created OK
//
BOOL CreateCheckboxImageList(CDC *pDC, 
                             CImageList& imagelist, 
                             int nSize, 
                             COLORREF crBackground)
{
    ASSERT(pDC);
    ASSERT(nSize > 0);

    BOOL rc = FALSE;

    ///////////////////////////////////////////////////////////////////////////
    //
    // CHECKBOX IMAGES
    //
    // From MSDN:  "To indicate that the item has no state image, set the
    //             index to zero. This convention means that image zero in 
    //             the state image list cannot be used as a state image."
    //
    // Note that comparable hot image = cold image index OR 8.
    // Disabled state = index OR 4.
    
    struct CHECKBOXDRAWDATA
    {
        TCHAR * pszDesc;    // description for debugging
        int nStateId;        // for DrawThemeBackground
        UINT nState;        // for DrawFrameControl
    } 
    cbdd[] =
    {
        // cold -----------------------------------------------------------------------------------
/*0000*/_T("unused"),                0,                        0,
/*0001*/_T("unchecked normal"),        CBS_UNCHECKEDNORMAL,    DFCS_BUTTONCHECK | DFCS_FLAT,
/*0010*/_T("checked normal"),        CBS_CHECKEDNORMAL,        DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_FLAT,
/*0011*/_T("tri-state normal"),        CBS_MIXEDNORMAL,        DFCS_BUTTON3STATE | DFCS_CHECKED | DFCS_FLAT,
/*0100*/_T("unused"),                0,                        0,
/*0101*/_T("unchecked disabled"),    CBS_UNCHECKEDDISABLED,    DFCS_BUTTONCHECK | DFCS_INACTIVE | DFCS_FLAT,
/*0110*/_T("checked disabled"),        CBS_CHECKEDDISABLED,    DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_INACTIVE | DFCS_FLAT,
/*0111*/_T("tri-state disabled"),    CBS_MIXEDDISABLED,        DFCS_BUTTON3STATE | DFCS_CHECKED | DFCS_INACTIVE | DFCS_FLAT,

        // hot ------------------------------------------------------------------------------------
/*1000*/_T("unused"),                0,                        0,
/*1001*/_T("unchecked normal"),        CBS_UNCHECKEDHOT,        DFCS_BUTTONCHECK | DFCS_FLAT,
/*1010*/_T("checked normal"),        CBS_CHECKEDHOT,            DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_FLAT,
/*1011*/_T("tri-state normal"),        CBS_MIXEDHOT,            DFCS_BUTTON3STATE | DFCS_CHECKED | DFCS_FLAT,
/*1100*/_T("unused"),                0,                        0,
/*1101*/_T("unchecked disabled"),    CBS_UNCHECKEDDISABLED,    DFCS_BUTTONCHECK | DFCS_INACTIVE | DFCS_FLAT,
/*1110*/_T("checked disabled"),        CBS_CHECKEDDISABLED,    DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_INACTIVE | DFCS_FLAT,
/*1111*/_T("tri-state disabled"),    CBS_MIXEDDISABLED,        DFCS_BUTTON3STATE | DFCS_CHECKED | DFCS_INACTIVE | DFCS_FLAT,

        NULL, 0, 0        // last entry
    };

    if (pDC && (nSize > 0))
    {
        const int nBmpWidth = nSize;
        const int nBmpHeight = nSize;
        const int nImages = sizeof(cbdd)/sizeof(cbdd[0]);
        ASSERT(nImages == 17);

        if (imagelist.GetSafeHandle())
            imagelist.DeleteImageList();

        CBitmap bmpCheckboxes;

        if (bmpCheckboxes.CreateCompatibleBitmap(pDC, nBmpWidth * nImages, 
                nBmpHeight))
        {
            if (imagelist.Create(nBmpWidth, nBmpHeight, ILC_COLOR32 | ILC_MASK, 
                    nImages, 1))
            {
                CDC dcMem;
                if (dcMem.CreateCompatibleDC(pDC))
                {
                    CBitmap* pOldBmp = dcMem.SelectObject(&bmpCheckboxes);
                    dcMem.FillSolidRect(0, 0, nBmpWidth*nImages, nBmpHeight, 
                        crBackground);

                    int nImageWidth  = nBmpWidth - 2;        // allow 2 for border
                    int nImageHeight = nBmpHeight - 2;
                    int nImageLeft   = (nBmpWidth - nImageWidth) / 2;
                    int nImageTop    = (nBmpHeight - nImageHeight) / 2;

                    CRect rectImage(nImageLeft, 
                                    nImageTop, 
                                    nImageLeft+nImageWidth, 
                                    nImageTop+nImageHeight);

                    for (int i = 0; cbdd[i].pszDesc != NULL; i++)
                    {
                        if (_tcscmp(cbdd[i].pszDesc, _T("unused")) == 0)
                        {
                            // unused image slot
                            // note that we skip the first image - they are 1-based
                        }
                        else
                        {
                            {
                                dcMem.DrawFrameControl(&rectImage, DFC_BUTTON, 
                                    cbdd[i].nState);
                            }
                        }

                        rectImage.left  += nBmpWidth;
                        rectImage.right += nBmpWidth;
                    }

                    dcMem.SelectObject(pOldBmp);
                    imagelist.Add(&bmpCheckboxes, RGB(255,0,255));

                    rc = TRUE;
                }
                else
                {
                    TRACE(_T("ERROR - failed to create DC\n"));
                }
            }
            else
            {
                TRACE(_T("ERROR - failed to create image list\n"));
            }
        }
        else
        {
            TRACE(_T("ERROR - failed to create bitmap\n"));
        }
    }
    else
    {
        TRACE(_T("ERROR - bad parameters\n"));
    }
    return rc;
}

}    // namespace
